﻿#region Copyright ©2008-2011, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-06-09 09:28:29 +0200 (Tue, 09 Jun 2009) $
// Last Changed Revision $Rev: 185 $
//
// ====================================================================================================
#endregion

using System.IO;
using System.Xml;
using System.Collections.Generic;
using Tum.CollabXT.TFS.Resources;
using System;


namespace Tum.CollabXT.TFS
{
    class WSS : IProcessor
    {
        string LibraryOutputFolder;
        XmlNode DocumentLibrariesNode;
        XmlNode FoldersNode;
        XmlNode FilesNode;

        public string TaskFileFolder
        {
            get;
            set;
        }

        public string TaskFileName
        {
            get;
            set;
        }


        public bool Process(TemplateProcessor processor)
        {
            processor.ToolProvider.ProcessLog.AddEntry(Language.Processing_WSS);
            string wssTemplateFileName = processor.ToolProvider.OutputPath + "/" + TaskFileFolder + "/" + TaskFileName;

            #region Load template
            XmlDocument wssDoc = new XmlDocument();
            processor.ToolProvider.ProcessLog.AddEntry(Language.WSS_Loading);
            try
            {
                wssDoc.Load(wssTemplateFileName);
            }
            catch
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_LoadingFailed, wssTemplateFileName), LogEntryType.Error);
                return false;
            }
            #endregion

            //Compose folder path
            LibraryOutputFolder = processor.ToolProvider.OutputPath + "/" + TaskFileFolder;

            #region Prepare needed template nodes
            const string portalNodePath = "/tasks/task[@plugin='Microsoft.ProjectCreationWizard.Portal']/taskXml/Portal";
            
            //Select needed nodes from template
            processor.ToolProvider.ProcessLog.AddEntry(Language.WSS_SelectingLibrariesNode);
            DocumentLibrariesNode = wssDoc.SelectSingleNode(portalNodePath + "/documentLibraries");
            if (DocumentLibrariesNode == null)
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_NotFound_InvalidTemplate, wssTemplateFileName + ": " + portalNodePath + "/documentLibraries"));
                return false;
            }

            processor.ToolProvider.ProcessLog.AddEntry(Language.WSS_SelectingFoldersNode);
            FoldersNode = wssDoc.SelectSingleNode(portalNodePath + "/folders");
            if (FoldersNode == null)
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_NotFound_InvalidTemplate, wssTemplateFileName + ": " + portalNodePath + "/folders"), LogEntryType.Error);
                return false;
            }

            processor.ToolProvider.ProcessLog.AddEntry(Language.WSS_SelectingFilesNode);
            FilesNode = wssDoc.SelectSingleNode(portalNodePath + "/files");
            if (FilesNode == null)
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_NotFound_InvalidTemplate, wssTemplateFileName + ": " + portalNodePath + "/files"), LogEntryType.Error);
                return false;
            }
            #endregion


            #region Write document libraries and folders
            List<string> writtenLibraries = new List<string>();

            //Get process guidance name from template configuration
            var processGuidanceNode = processor.TemplateConfigDocument.SelectSingleNode("//Tasks.Portal/ProcessGuidanceName");
            if (processGuidanceNode == null || processGuidanceNode.InnerText.Trim().Length == 0)
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_NotFound_InvalidTemplate, "Template config: //Tasks.Portal/ProcessGuidanceName"), LogEntryType.Error);
                return false;
            }
            string processGuidanceName = processGuidanceNode.InnerText;

            //Write process guidance
            if (!string.IsNullOrEmpty(processor.ToolProvider.ProcessGuidancePath) && Directory.Exists(processor.ToolProvider.ProcessGuidancePath))
            {
                //Write default PG page document if necessary
                string pgFolder = LibraryOutputFolder + "/" + processGuidanceName;
                string defPgFilePath = pgFolder + "/ProcessGuidance.html";
                if (!string.IsNullOrEmpty(processor.ToolProvider.ProcessGuidanceDefaultPage) && !File.Exists(defPgFilePath))
                {
                    Directory.CreateDirectory(pgFolder);

                    using (StreamWriter defPgFileWriter = new StreamWriter(defPgFilePath))
                    {
                        defPgFileWriter.WriteLine("<meta http-equiv=\"refresh\" content=\"0;URL=" + processor.ToolProvider.ProcessGuidanceDefaultPage + "\" >");
                        defPgFileWriter.Close();
                    }
                }

                //Write PG document library
                WriteDocumentLibrary(processGuidanceName, processor.ToolProvider.ProcessGuidancePath, processor.ToolProvider.OutputPath, true);
                writtenLibraries.Add(processGuidanceName);
            }

            //Write additional libraries
            foreach (KeyValuePair<string, string> curLibrary in processor.ToolProvider.DocumentLibraries)
            {
                //Do not write two libraries with same name
                foreach (var existingLibraryName in writtenLibraries)
                {
                    if (existingLibraryName.Equals(curLibrary.Key, StringComparison.InvariantCultureIgnoreCase))
                    {
                        processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_DuplicateLibraryName, existingLibraryName), LogEntryType.Error);
                        return false;
                    }
                }

                //Write library
                WriteDocumentLibrary(curLibrary.Key, curLibrary.Value, processor.ToolProvider.OutputPath, false);
            }
            #endregion

            #region Save WSS file
            processor.ToolProvider.ProcessLog.AddEntry(Language.WSS_Saving);
            try
            {
                wssDoc.Save(wssTemplateFileName);
            }
            catch
            {
                processor.ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_SavingFailed, wssTemplateFileName), LogEntryType.Error);
                return false;
            }
            #endregion

            return true;
        }

        /// <summary>
        /// Creates a new document library in the template
        /// </summary>
        private void WriteDocumentLibrary(string libraryName, string sourceFolder, string outputFolder, bool isProcessGuidance)
        {
            string libraryFolder = LibraryOutputFolder + "/" + libraryName;

            //Create library folder and copy files to it
            Directory.CreateDirectory(libraryFolder);
            Helper.CopyDirectory(sourceFolder, libraryFolder);

            //Normalize folder path
            libraryFolder = new DirectoryInfo(libraryFolder).FullName;

            #region Add document library node
            XmlNode docLibNode = DocumentLibrariesNode.OwnerDocument.CreateElement("documentLibrary");

            //Name
            XmlAttribute nameAttribute = DocumentLibrariesNode.OwnerDocument.CreateAttribute("name");
            nameAttribute.Value = libraryName;
            docLibNode.Attributes.Append(nameAttribute);

            //Description
            XmlAttribute descriptionAttribute = DocumentLibrariesNode.OwnerDocument.CreateAttribute("description");
            descriptionAttribute.Value = libraryName;
            docLibNode.Attributes.Append(descriptionAttribute);

            //Process Guidance
            if (isProcessGuidance)
            {
                XmlAttribute pgAttribute = DocumentLibrariesNode.OwnerDocument.CreateAttribute("isProcessGuidance");
                pgAttribute.Value = "true";
                docLibNode.Attributes.Append(pgAttribute);
            }

            //Add node and save library name
            DocumentLibrariesNode.AppendChild(docLibNode); 
            #endregion

            WriteChildFolders(libraryName, libraryFolder, libraryFolder, outputFolder);
        }

        /// <summary>
        /// Write folders section for a specific folder of a document library and its subfolders.
        /// </summary>
        /// <param name="curFolderPath">Folder for which the current node is to be written.</param>
        private void WriteChildFolders(string libraryName, string libraryFolderPath, string curFolderPath, string outputFolder)
        {
            //Write folder
            foreach (string curChildFolder in Directory.GetDirectories(curFolderPath))
            {
                //Create path format required for process template
                string normalizedFolderPath = curChildFolder.Substring(libraryFolderPath.Length + 1).Replace('\\', '/');

                //Check if folder node already exists
                if (FoldersNode.SelectNodes("folder[@documentLibrary='" + libraryName + "'][@name='" + normalizedFolderPath + "']").Count == 0)
                {
                    //Does not exist yet, write it
                    XmlNode newFolderNode = FoldersNode.OwnerDocument.CreateElement("folder");
                    XmlAttribute docLibraryAttribute = FoldersNode.OwnerDocument.CreateAttribute("documentLibrary");
                    docLibraryAttribute.Value = libraryName;
                    newFolderNode.Attributes.Append(docLibraryAttribute);
                    XmlAttribute nameAttribute = FoldersNode.OwnerDocument.CreateAttribute("name");
                    nameAttribute.Value = normalizedFolderPath;
                    newFolderNode.Attributes.Append(nameAttribute);
                    FoldersNode.AppendChild(newFolderNode);
                }

                //Continue recursively
                WriteChildFolders(libraryName, libraryFolderPath, curChildFolder, outputFolder);
            }

            //Write files
            string normalizedOutputFolderPath = new DirectoryInfo(outputFolder).FullName;
            foreach (string curFilePath in Directory.GetFiles(curFolderPath))
            {
                string localFilePath = curFilePath.Substring(libraryFolderPath.Length + 1).Replace('\\', '/');

                //Check if file node already exists
                if (FilesNode.SelectNodes("file[@documentLibrary='" + libraryName + "'][@target='" + localFilePath + "']").Count == 0)
                {
                    XmlNode newFileNode = FilesNode.OwnerDocument.CreateNode("element", "file", string.Empty);

                    XmlAttribute targetAttribute = FilesNode.OwnerDocument.CreateAttribute("target");
                    targetAttribute.Value = localFilePath;
                    newFileNode.Attributes.Append(targetAttribute);

                    XmlAttribute docLibraryAttribute = FilesNode.OwnerDocument.CreateAttribute("documentLibrary");
                    docLibraryAttribute.Value = libraryName;
                    newFileNode.Attributes.Append(docLibraryAttribute);

                    XmlAttribute sourceAttribute = FilesNode.OwnerDocument.CreateAttribute("source");
                    sourceAttribute.Value = curFilePath.Substring(normalizedOutputFolderPath.Length).Replace('\\', '/');
                    newFileNode.Attributes.Append(sourceAttribute);

                    FilesNode.AppendChild(newFileNode);
                }
            }
        }
    }
}
